AssumeRoleの一時クレデンシャルが有効期限切れなら再認証させるシェルスクリプトを作ってみた(zsh)
こんにちは、CX事業本部 IoT事業部の若槻です。
作業環境などでAWSコマンドの認証をAssumeRoleで行いたい時には、aws sts assume-role
で取得した一時クレデンシャルの情報を環境変数に格納して使用することが多いのではないでしょうか。
しかしこの取得した一時クレデンシャルが有効期限内であるかどうかを知るためには、実際にAWS CLIコマンドを試してエラーなく実行できるかを確認する必要があり、ひと手間掛かるのが不便です。
今回は、AssumeRoleの一時クレデンシャルが期限切れなら再認証させるシェルスクリプトを作ってみました。
前提
使用するシェルはzshです。Macだとデフォルトのシェルですね。
$ echo $SHELL /bin/zsh $ zsh --version zsh 5.8 (x86_64-apple-darwin20.0)
またAssumeRoleに使用するIAMユーザーにはMFAが設定されている前提とします。
シェルスクリプト
次のようなシェルスクリプトを作ってみました。
#!/bin/zsh set -e ## 一時クレデンシャルのセッション有効期限を指定 SESSION_DURATION_SECONDS=$((60*60*12)) ## 現在より SESSION_DURATION_SECONDS 前の日時(Unixtime)を取得 session_duration_unixtime=$(date -v -${SESSION_DURATION_SECONDS}S +%s) ## 最終認証日時(Unixtime)を環境変数から取得 last_assumed_unixtime=${LAST_ASSUMED_UNIXTIME:-0} ## セッション有効期限切れなら再認証する if [[ ${last_assumed_unixtime} -lt ${session_duration_unixtime} ]]; then echo "再認証します。MFAコードを入力してください。" ## MFAコードをキーボード入力で受付け read mfa_code ## 認証 AWS_STS_CREDENTIALS=`aws sts assume-role \ --profile default \ --role-arn $(aws configure get ${target_profile}.role_arn) \ --role-session-name ${target_profile}-session \ --serial-number $(aws configure get ${target_profile}.mfa_serial) \ --duration-seconds ${SESSION_DURATION_SECONDS} \ --token-code ${mfa_code}` export AWS_ACCESS_KEY_ID=`echo "${AWS_STS_CREDENTIALS}" | jq -r '.Credentials.AccessKeyId'` export AWS_SECRET_ACCESS_KEY=`echo "${AWS_STS_CREDENTIALS}" | jq -r '.Credentials.SecretAccessKey'` export AWS_SESSION_TOKEN=`echo "${AWS_STS_CREDENTIALS}" | jq -r '.Credentials.SessionToken'` ## 最終認証日時(Unixtime)を環境変数に設定 export LAST_ASSUMED_UNIXTIME=$(date +%s) else echo "セッションが有効期限内のため、再認証不要です。" fi
このスクリプト内では次のようなことをしています。
- 一時クレデンシャルの任意のセッション有効期限を指定
- 現在より有効期限の期間以前の日時(Unixtime)を取得
- 最終認証日時(Unixtime)を環境変数から取得(未定義なら
0
となる) - セッション有効期限切れ(2の値より3の値が大きい)であるか判定(以下、有効期限切れの場合)
- MFAコードをキーボード入力で受付け
- AssumeRoleによる認証実施
- 最終認証日時(Unixtime)を環境変数に設定
つまりスクリプト事項で認証を実施したらLAST_ASSUMED_UNIXTIME
に現在日時を設定し、次回スクリプト実行時にLAST_ASSUMED_UNIXTIME
の値を取得して再認証が必要か判断し、必要なら行うという内容です。
使ってみる
(初回のみ)スクリプトファイルの権限を設定して実行可能にします。
$ chmod 744 update-aws-credential.sh
使用したいプロファイル名(~/.aws/credentials
内で指定している名前)を環境変数target_profile
に指定しておきます。
$ export target_profile=some-profile-name
未認証(LAST_ASSUMED_UNIXTIME未定義)の場合
まず、スクリプトによる認証を一度も行っていない状態の場合です。この時点ではLAST_ASSUMED_UNIXTIME
が未定義となっています。
$ echo $LAST_ASSUMED_UNIXTIME
そしてスクリプトを実行するのですが、この時source
を必ず使用します。これによりシェルスクリプト内で環境変数に設定した一時クレデンシャルの情報が呼び出し元のシェルにも反映され使えるようになります。
実行するとMFAコードの入力を求められるので指定します。
$ source ./update-aws-credential.sh 再認証します。MFAコードを入力してください。
認証が成功しました!
認証が成功し、一時クレデンシャルが設定されたのでAssumeRole後のセッションでAWS CLIが実行可能となっています。
$ aws sts get-caller-identity { "UserId": "AROAUL6WVPY2E4JAUAR6D:some-profile-name-session", "Account": "XXXXXXXXXXXX", "Arn": "arn:aws:sts::XXXXXXXXXXXX:assumed-role/cm-wakatsuki.ryuta/some-profile-name-session" }
認証済み(LAST_ASSUMED_UNIXTIMEが有効期限内)の場合
次に、スクリプトによる認証がセッション有効期限内に実施されている場合です。この時点ではLAST_ASSUMED_UNIXTIME
に有効期限内の時間が設定されています。
$ echo $LAST_ASSUMED_UNIXTIME 1643126192
再認証不要のため認証は求められませんでした!
$ source ./update-aws-credential.sh セッションが有効期限内のため、再認証不要です。
認証期限切れ(LAST_ASSUMED_UNIXTIMEが有効期限以前)の場合
次に、スクリプトによる認証がセッション有効期限以前に実施されている場合です。
明らかに有効期間外のUnixtimeをLAST_ASSUMED_UNIXTIME
に設定してみます。
$ export LAST_ASSUMED_UNIXTIME=12345
MFAコードが求められ、指定すると認証が行えました!
$ source ./update-aws-credential.sh 再認証します。MFAコードを入力してください。 824093
ハマった箇所
zshとbashの文法の違い
zshとbashでは文法が微妙に違うのですが、ネットの情報にはbashが多いため、zshの文法を確認するのに苦労しました。
例えば、if文のConditionの指定は、bashが[]
なのに対し、zshは[[]]
となります。
## bash if [a -lt b]; then echo "bashの場合" fi ## zsh if [[a -lt b]]; then echo "zshの場合" fi
他には、date
コマンドで過去の日時を取得する場合、指定の仕方が違ってきます。
## bash date -d '1 days' +%Y%m%d ## zsh date -v '+1d' +%Y%m%d
環境変数未定義を許容
シェルスクリプト冒頭でset -eu
とすると、環境変数が未定義の場合に実行が停止してしまいます。よって-u
オプションを使わずset -e
と記述する必要がありました。
おわりに
AssumeRoleの一時クレデンシャルが期限切れなら再認証させるシェルスクリプトを作ってみました。
このシェルスクリプトを単独で使うもよし、他のAWSコマンドなどを実行するスクリプトに組み込むも良し、です。
私は下記のスクリプトに組み込んでみようと思います。
参考
- AssumeRole(スイッチロール)で一時クレデンシャルを取得して環境変数にセットするワンライナー | DevelopersIO
- 【Linux】シェルスクリプトでキーボード入力を受付ける方法
- シェルスクリプトで環境変数を設定する
- Perl/bash/zsh で今と昨日と一時間前を出すコピペ
- zsh conditional OR fails - Stack Overflow
- シェルスクリプトを書くときはset -euしておく - Qiita
以上